package main.connectionpool;


import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class ConnectionPool {

    private final int minConnections;
    private final int maxConnections;
    private final String uri;

    private AtomicInteger usedConnections = new AtomicInteger(0);
    private AtomicInteger requests = new AtomicInteger(0);

    private BlockingQueue<ConnectionFromPool> connections;


    public ConnectionPool(int minConnections, int maxConnections, String uri) {
        this.minConnections = minConnections;
        this.maxConnections = maxConnections;
        this.uri = uri;

        connections = new LinkedBlockingQueue<>(minConnections);
    }

    public int getUsedConnections() {
        return usedConnections.get();
    }

    public int getFreeConnections() {
        return minConnections - connections.remainingCapacity();
    }


    public ConnectionFromPool getConnection() throws InterruptedException {
        return getConnection(0, TimeUnit.MILLISECONDS);
    }

    public ConnectionFromPool getConnectionBlocking() throws InterruptedException {
        return getConnection(Long.MAX_VALUE, TimeUnit.DAYS);
    }

    public ConnectionFromPool getConnection(long timeout, TimeUnit unit) throws InterruptedException {

        ConnectionFromPool connectionFromPool = connections.poll();

        if (connectionFromPool == null) {
            if (usedConnections.get() + requests.getAndIncrement() < maxConnections) {
                connectionFromPool = openConnection();
            } else {
                connectionFromPool = connections.poll(timeout, unit);
            }
            requests.decrementAndGet();
        }

        usedConnections.incrementAndGet();
        return connectionFromPool;

    }

    public void rebase(ConnectionFromPool connectionFromPool) throws InterruptedException, SQLException {

        if (usedConnections.decrementAndGet() < 0) throw new IllegalStateException("No used connections to rebase");

        if (!connections.offer(connectionFromPool)) {
            connectionFromPool.getConnection();//.close();
        }
    }

    private ConnectionFromPool openConnection() {
        //stub
        Connection connection = null;
        return new ConnectionFromPool(connection);
    }


}
